import os
import time
import logging

class Recorder():
    def __init__(self, widget):
        self.widget = widget
        self.max_lines = 4000
        self.times = 0
        self.indexs = []
        self.widget.tag_config('r',foreground = 'red')
        self.widget.tag_config('lr',foreground = '#FF4040')  # light red
        self.widget.tag_config('g',foreground = '#08AE51')
        self.logger = logging.getLogger('log.recorder')

    def record(self, msg, end='\n', index='end', tag=None, set_index=None, unset_index=None):
        self.times += 1
        total_lines = 1
        if self.times > 200:
            time.sleep(1.0)
            try:
                total_lines = int(self.widget.index('end').split('.')[0])
            except Exception:
                self.logger.exception("exception when get the total lines.")
                total_lines = 1
            else:
                self.times = 0

#         while True:
#             try:
#                 self.widget.config(state='normal')
#             except Exception:
#                 self.logger.exception("exception set recorder to normal")
#                 time.sleep(0.1)
#             else:
#                 break

        try:
            time.sleep(0.1)
            self.widget.config(state='normal')
            if total_lines > self.max_lines:
                self.widget.delete(1.0, 1000.0)
            self.widget.insert(index, msg + end, tag)
            time.sleep(0.1)  # wait widget insert complete
            if set_index:
                self.mark_set(set_index)
            if unset_index:
                self.mark_unset(unset_index)
            self.widget.config(state='disable')
            self.widget.yview('end')
        except Exception:
            logger = logging.getLogger('log.recorder')
            logger.exception("exception when insert msg(%s)." % msg)

    def mark_set(self, index):
        # force insert index to the end, due to user change the cursor
        while True:
            try:
                self.widget.mark_set("insert", self.widget.index('end'))
            except Exception:
                time.sleep(0.1)
            else:
                break
        if index not in self.indexs:
            self.indexs.append(index)
        self.widget.mark_set(index, 'insert-1c')

    def mark_unset(self, index):
        if index in self.indexs:
            self.indexs.remove(index)
            self.widget.mark_unset(index)

    def clear(self):
        self.widget.config(state='normal')
        self.widget.delete(1.0, 'end')
        time.sleep(0.2)
        self.widget.config(state='disable')


class RecordFile(Recorder):
    def __init__(self, name, set_file, widget):
        Recorder.__init__(self, widget)
        self.name = name
        self.fh = None
        if set_file:
            self.set_record_file()

    def __del__(self):
        if self.fh:
            self.fh.close()

    def set_record_file(self):
        self.logger = logging.getLogger('log.record.%s' % self.name)
        log_path = os.path.join(os.getcwd(), "log")
        if not os.path.isdir(log_path):
            os.makedirs(log_path)
        seconds = int(time.time())
        for times in xrange(50):
            t = time.strftime('%Y%m%d_%H%M%S', time.gmtime(seconds+times))
            log_file = os.path.join(log_path, "%s_%s.txt" % (t, self.name))
            if not os.path.isfile(log_file):
                break
        try:
            self.logger.debug("start record file %s." % log_file)
            self.fh = open(os.path.join(log_path, log_file), 'a')
        except Exception:
            self.fh = None
            self.logger.exception("failed to open file %s" % self.name)

    def write_file(self, msg):
        if self.fh:
            try:
                self.fh.write(msg)
            except Exception:
                self.logger.exception("failed to write - %s" % msg)

    def write(self, msg, **kwargs):
        if not kwargs.has_key('end'):
            kwargs['end'] = ''
        self.record(msg, **kwargs)
        self.write_file(msg)

class RecordLogger(Recorder):
    def __init__(self, widget):
        Recorder.__init__(self, widget)
        self.logger = logging.getLogger('log')

    def str_record(self, msg, head):
        if head:
            return "%s: %s" % (head, msg)
        else:
            return msg

    def str_logger(self, msg, head):
        if head:
            return "%s - %s" % (head, msg)
        else:
            return msg

    def _func_logger(self, func_name, msg):
        if self.logger and hasattr(self.logger, func_name):
            getattr(self.logger, func_name)(msg)

    def notice(self, msg, head='', **kwargs):
        self.record(self.str_record(msg, head), **kwargs)

    def debug(self, msg, head='', **kwargs):
        self._func_logger('debug', self.str_logger(msg, head))

    def info(self, msg, head='', **kwargs):
        if not kwargs.has_key('record'):
            kwargs['record'] = True
        if kwargs.pop('record'):
            self.record(self.str_record(msg, head), **kwargs)
        self._func_logger('info', self.str_logger(msg, head))

    def warning(self, msg, head='', **kwargs):
        kwargs['tag'] = 'lr'
        if not kwargs.has_key('record'):
            kwargs['record'] = True
        if kwargs.pop('record'):
            self.record(self.str_record("Warning: "+msg, head), **kwargs)
        self._func_logger('warning', self.str_logger(msg, head))

    warn = warning

    def error(self, msg, head='', **kwargs):
        kwargs['tag'] = 'r'
        if not kwargs.has_key('record'):
            kwargs['record'] = True
        if kwargs.pop('record'):
            self.record(self.str_record("Error: "+msg, head), **kwargs)
        self._func_logger('error', self.str_logger(msg, head))

    def exception(self, msg, **kwargs):
        self._func_logger('exception', msg)
